package com.hanxiaozhang.system.service.impl;

import com.hanxiaozhang.constant.CacheName;
import com.hanxiaozhang.constant.DelFlagEnum;
import com.hanxiaozhang.result.ResultCode;
import com.hanxiaozhang.result.Result;
import com.hanxiaozhang.security.CurrentUserUtil;
import com.hanxiaozhang.system.dao.RoleMenuDao;
import com.hanxiaozhang.system.dao.UserRoleDao;
import com.hanxiaozhang.system.dto.RoleDTO;
import com.hanxiaozhang.system.entity.RoleMenuEntity;
import com.hanxiaozhang.system.entity.UserRoleEntity;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import com.hanxiaozhang.system.dao.RoleDao;
import com.hanxiaozhang.system.service.RoleService;
import org.springframework.transaction.annotation.Transactional;


/**
 * 角色表
 *
 * @author hanxiaozhang
 * @email hanxiaozhang2018@sina.com
 * @date 2021-03-31
 */
@Service
public class RoleServiceImpl implements RoleService {

    @Resource
    private RoleDao roleDao;
    @Resource
    private RoleMenuDao roleMenuDao;
    @Resource
    private UserRoleDao userRoleDao;

    @Override
    public RoleDTO get(Long roleId) {
        return roleDao.get(roleId);
    }

    @Override
    public List<RoleDTO> list(Map<String, Object> map) {
        return roleDao.list(map);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = {CacheName.CURRENT_USER_BY_USER_ID_2HOUR, CacheName.ROUTE_BY_USER_ID_2HOUR}, allEntries = true)
    public int save(RoleDTO role) {

        List<Long> menuIds = role.getMenuIds();
        String userName = CurrentUserUtil.getUserName();
        LocalDateTime now = LocalDateTime.now();
        role.setCreateBy(userName)
                .setCreateDate(now)
                .setDelFlag(DelFlagEnum.NORMAL.getCode());
        roleDao.save(role);

        if (!menuIds.isEmpty()) {
            Long roleId = role.getRoleId();
            saveRoleMenu(menuIds, roleId, userName, now);
        }
        return 1;
    }

    /**
     * 更新角色
     *
     * 更新角色清除所有路由和当前用户缓存，
     * PS：应该手动精准清除该角色对应用户的缓存
     *
     * @param role
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = {CacheName.CURRENT_USER_BY_USER_ID_2HOUR, CacheName.ROUTE_BY_USER_ID_2HOUR}, allEntries = true)
    public int update(RoleDTO role) {
        List<Long> menuIds = role.getMenuIds();
        String userName = CurrentUserUtil.getUserName();
        LocalDateTime now = LocalDateTime.now();
        if (!menuIds.isEmpty()) {
            Long roleId = role.getRoleId();
            roleMenuDao.removeByRoleId(roleId);
            saveRoleMenu(menuIds, roleId, userName, now);
        }

        role.setUpdateBy(CurrentUserUtil.getUserName())
                .setUpdateDate(LocalDateTime.now());
        return roleDao.update(role);
    }

    /**
     * 保存关联关系
     *
     * @param menuIds
     * @param roleId
     * @param userName
     * @param now
     */
    private void saveRoleMenu(List<Long> menuIds, Long roleId, String userName, LocalDateTime now) {
        List<RoleMenuEntity> roleMenuList = new ArrayList<>();
        menuIds.forEach(x -> {
            if (x == null) {
                return;
            }
            RoleMenuEntity roleMenu = new RoleMenuEntity();
            roleMenu.setMenuId(x)
                    .setRoleId(roleId)
                    .setCreateBy(userName)
                    .setCreateDate(now)
                    .setDelFlag(DelFlagEnum.NORMAL.getCode());
            roleMenuList.add(roleMenu);
        });
        roleMenuDao.batchSave(roleMenuList);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = {CacheName.CURRENT_USER_BY_USER_ID_2HOUR, CacheName.ROUTE_BY_USER_ID_2HOUR}, allEntries = true)
    public Result remove(Long roleId) {
        List<UserRoleEntity> list = userRoleDao.listByRoleId(roleId);
        if (!list.isEmpty()) {
            return Result.error(ResultCode.DATA_EXISTED_RELATION);
        }
        roleDao.remove(roleId);
        roleMenuDao.removeByRoleId(roleId);
        return Result.success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = {CacheName.CURRENT_USER_BY_USER_ID_2HOUR, CacheName.ROUTE_BY_USER_ID_2HOUR}, allEntries = true)
    public Result batchRemove(Long[] roleIds) {
        List<UserRoleEntity> list = userRoleDao.listByRoleIds(Arrays.asList(roleIds));
        if (!list.isEmpty()) {
            return Result.error(ResultCode.DATA_EXISTED_RELATION);
        }
        roleDao.batchRemove(roleIds);
        roleMenuDao.batchRemoveByRoleIds(roleIds);
        return Result.success();
    }

}
